Skip to content

Power spectral density curves settings improvement #844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 35 commits into
base: master
Choose a base branch
from

Conversation

demvlad
Copy link
Contributor

@demvlad demvlad commented Jul 4, 2025

The vertical slider is changed to numerical input fields.
The older vertical slider had different function by compare with other spectrums, what was unlogical.
This settings shows points per segment for PSD computing by using Welch method.
This value is power at 2. The bigger segment length gives bigger spectrum frequency resolution, but the less segments length gives smoother result. The maximal value is limited by data samples count.

The new number input field:
psd1
psd2

The olde vertical slider:
olde

Summary by CodeRabbit

  • New Features

    • Added a numeric input field for specifying segment length in Power Spectral Density (PSD) analysis, allowing values between 64 and 1,048,576.
    • Included labeled controls to configure legend position and size in analyser settings.
    • Enabled importing and removal of frequency and PSD curves from CSV files with visual representation and legend support.
    • Added user settings to customize legend layout in the analyser panel.
  • Style

    • Updated styles to ensure the new segment length input, label, and legend controls are visually consistent and well-positioned within the analyser panel.
  • Bug Fixes

    • Improved input validation to ensure only valid segment lengths (powers of two) can be selected for PSD analysis.

Copy link

coderabbitai bot commented Jul 4, 2025

## Walkthrough

A numeric input for segment length was added to the analyser's Power Spectral Density (PSD) controls in the UI. The input is integrated into the UI logic, PSD calculation module, and CSS. The PSD calculation now uses this user-defined segment length, and related event handling and state management were updated accordingly. Additionally, imported curve management was modularized, legend positioning controls were added, and export logic was refined.

## Changes

| File(s)                                    | Change Summary                                                                                                                   |
|--------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| index.html                                 | Added numeric input and label for PSD segment length and legend position/size inputs in analyser settings and user settings dialog. |
| src/css/main.css                           | Added and updated styles for the new PSD segment length input and its label for consistent appearance and positioning.           |
| src/graph_spectrum.js                      | Integrated segment length input into UI logic, event handling, and PSD data reloading; updated state management and visibility; simplified CSV import; added methods to remove imported spectrums and get export filename.  |
| src/graph_spectrum_calc.js                 | Added segment length property and setter; updated PSD calculation to use user-defined segment length; adjusted overlap logic; renamed return fields.    |
| public/js/webworkers/spectrum-export-worker.js | Modified FFT data export to include all data points with new CSV headers.                                                        |
| src/graph_imported_curves.js               | Added new module managing imported curves from CSV files with import, count, and removal functionality.                          |
| src/graph_spectrum_plot.js                  | Refactored imported spectrum handling to use ImportedCurves instances; updated drawing logic for frequency and PSD graphs; added legend drawing with user-configured layout; replaced frequency constants; added import/remove curve methods. |
| src/main.js                                | Updated exportSpectrumToCsv to use dynamic filename from analyser; renamed method to remove imported spectrums; updated button handlers accordingly. |
| src/user_settings_dialog.js                 | Added new analyser_legend settings group with left, top, and width properties; updated UI-to-settings and settings-to-UI conversions. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant User
    participant UI (index.html)
    participant GraphSpectrum
    participant GraphSpectrumCalc

    User->>UI (index.html): Change segment length input
    UI (index.html)->>GraphSpectrum: Input event triggers handler
    GraphSpectrum->>GraphSpectrumCalc: setPointsPerSegmentPSD(newLength)
    GraphSpectrum->>GraphSpectrumCalc: dataLoadPSD()
    GraphSpectrumCalc-->>GraphSpectrum: Returns PSD data
    GraphSpectrum->>UI (index.html): Update plot with new PSD data

Possibly related PRs

Suggested reviewers

  • haslinghuis

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=betaflight/blackbox-log-viewer&utm_content=844):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
index.html (1)

496-515: Wire up PSD segment-length persistence and restore

The segment-length control is correctly clamped to powers-of-two and toggled based on spectrum type, but it isn’t saved or initialized from user settings. Without this, users will lose their chosen segment length on refresh.

• In src/graph_spectrum.js, around line 302–304 (initialization):
– Load userSettings.psdSegmentLength (or fallback to DEFAULT_PSD_SEGMENT_LENGTH) before calling GraphSpectrumCalc.setPointsPerSegmentPSD(...) and set the input’s .val(...).

• In the .on("input", …) handler at line 304–318:
– After updating segmentLenghtPSD, call saveOneUserSetting("psdSegmentLength", segmentLenghtPSD).

Suggested diff snippet:

--- a/src/graph_spectrum.js
+++ b/src/graph_spectrum.js
@@ 300,7 +300,15 @@
-   let segmentLenghtPSD = DEFAULT_PSD_SEGMENT_LENGTH;
-   GraphSpectrumCalc.setPointsPerSegmentPSD(segmentLenghtPSD);
-   analyserSegmentLengthPSD
+   // Restore saved PSD segment length
+   let segmentLenghtPSD =
+     userSettings.psdSegmentLength ?? DEFAULT_PSD_SEGMENT_LENGTH;
+   analyserSegmentLengthPSD.val(segmentLenghtPSD);
+   GraphSpectrumCalc.setPointsPerSegmentPSD(segmentLenghtPSD);
+   saveOneUserSetting("psdSegmentLength", segmentLenghtPSD);
+   analyserSegmentLengthPSD
@@ 307,6 +315,7 @@
           $(this).val(segmentLenghtPSD);
           // Recalculate PSD with updated samples per segment count
           GraphSpectrumCalc.setPointsPerSegmentPSD(segmentLenghtPSD);
+          saveOneUserSetting("psdSegmentLength", segmentLenghtPSD);
           dataLoad();
           GraphSpectrumPlot.setData(fftData, userSettings.spectrumType);
           that.refresh();

This ensures the control’s value is persisted and restored.

🧹 Nitpick comments (2)
index.html (2)

496-497: Associate the new input with its label for accessibility

The new <input> lacks an explicit association with its descriptive label (<label id="analyserSegmentLengthPSDLabel">). Adding a for="analyserSegmentLengthPSD" attribute on the label (and keeping the input’s id) will let screen–reader and form–navigation tools recognise the relationship.

-<label id="analyserSegmentLengthPSDLabel" name="analyserSegmentLengthPSDLabel" class="onlyFullScreen" >
+<label for="analyserSegmentLengthPSD"
+       id="analyserSegmentLengthPSDLabel"
+       name="analyserSegmentLengthPSDLabel"
+       class="onlyFullScreen">

513-515: Minor wording: “Segment length” (singular) reads better

UI copy elsewhere uses singular nouns (“Limit dBm”, “Max dBm”). Consider changing the caption to “Segment length” for consistency and readability.

-  Segments&nbsp;length
+  Segment&nbsp;length
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95cbf3a and 1e3dda3.

📒 Files selected for processing (4)
  • index.html (2 hunks)
  • src/css/main.css (2 hunks)
  • src/graph_spectrum.js (8 hunks)
  • src/graph_spectrum_calc.js (3 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
Learnt from: Quick-Flash
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-13T17:48:20.477Z
Learning: When using FFT (Fast Fourier Transform), enforcing power-of-2 input lengths improves computational efficiency and numerical stability but can result in discarding up to almost 50% of the flight data in worst-case scenarios.
index.html (3)

undefined

<retrieved_learning>
Learnt from: demvlad
PR: #833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions dataLoadPowerSpectralDensityVsThrottle() and dataLoadPowerSpectralDensityVsRpm() instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
</retrieved_learning>

<retrieved_learning>
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
</retrieved_learning>

<retrieved_learning>
Learnt from: demvlad
PR: #827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
</retrieved_learning>

src/css/main.css (3)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
src/graph_spectrum.js (4)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
Learnt from: Quick-Flash
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-13T17:48:20.477Z
Learning: When using FFT (Fast Fourier Transform), enforcing power-of-2 input lengths improves computational efficiency and numerical stability but can result in discarding up to almost 50% of the flight data in worst-case scenarios.
src/graph_spectrum_calc.js (5)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
Learnt from: Quick-Flash
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-13T17:48:20.477Z
Learning: When using FFT (Fast Fourier Transform), enforcing power-of-2 input lengths improves computational efficiency and numerical stability but can result in discarding up to almost 50% of the flight data in worst-case scenarios.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
🔇 Additional comments (12)
src/css/main.css (2)

693-695: LGTM: Consistent spin button styling applied.

The CSS rule correctly extends the existing webkit spin button appearance overrides to include the new segment length input, maintaining visual consistency with other PSD inputs.


749-763: LGTM: Proper positioning and styling for new input controls.

The CSS positioning and styling for the segment length input and label follow the established pattern of other analyser controls, ensuring consistent appearance and layout.

src/graph_spectrum_calc.js (3)

38-38: LGTM: Appropriate property addition.

The new private property _pointsPerSegmentPSD properly stores the user-defined segment length for PSD calculations.


116-118: LGTM: Clean setter implementation.

The setter method provides a clean interface for updating the PSD segment length from the UI layer.


122-129: Excellent refactoring of PSD calculation logic.

The changes successfully decouple PSD segment length from zoom controls, allowing explicit user control. The logic appropriately handles edge cases where the requested segment length exceeds available samples, and the returned maximalSegmentsLength enables proper UI validation.

Note: The overlap calculation has changed from 50% to 75% (pointsPerSegment * 3 / 4), which will provide better frequency resolution at the cost of some computational overhead.

Also applies to: 142-142

src/graph_spectrum.js (7)

20-21: LGTM: Appropriate default value.

The default segment length of 512 is a good power-of-2 value that balances frequency resolution with computational efficiency.


39-39: LGTM: Consistent DOM element reference.

The new element reference follows the established naming pattern for other analyser controls.


122-127: LGTM: Proper positioning integration.

The positioning logic for the new segment length input and label is properly integrated with the existing resize functionality.


158-158: Excellent dynamic validation integration.

Setting the max property based on maximalSegmentsLength from the FFT data ensures the UI prevents invalid segment length values that exceed available data.


330-336: LGTM: Effective input restriction.

The keydown event handler properly prevents arbitrary input, ensuring only power-of-2 values can be set through the UI interaction logic.


362-372: Excellent UI state management.

The spectrum type change handling properly shows/hides the segment length control only for the POWER_SPECTRAL_DENSITY type, maintaining clean UI organization and following the established pattern for other spectrum-specific controls.

Also applies to: 397-400


253-253: LGTM: Simplified input handling.

Removing the conditional check before setting the low-level PSD value simplifies the logic appropriately.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 4, 2025
@demvlad
Copy link
Contributor Author

demvlad commented Jul 4, 2025

@mituritsyn, please, could you have look at this improvement

@mituritsyn
Copy link
Contributor

functionally it is good. Small visual notice - the signature looks a bit out of place, perhaps it would be bettre to slightly adjust the alignment.
I found an issue with the PSD plot filter display. The static notch is aligned with the wrong frequency, centered at 200 Hz, when it should be at 220 Hz.
image

image

It is appropriately aligned on the frequency plot.
image

coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 6, 2025
@demvlad
Copy link
Contributor Author

demvlad commented Jul 6, 2025

I found an issue with the PSD plot filter display. The static notch is aligned with the wrong frequency, centered at 200 Hz, when it should be at 220 Hz.

This was common issue for the all filters at the PSD curve chart only. Resolved.
filters_label

demvlad and others added 5 commits July 15, 2025 21:50
coderabbitai[bot]
coderabbitai bot previously approved these changes Jul 16, 2025
@demvlad
Copy link
Contributor Author

demvlad commented Jul 16, 2025

I think, maybe will better show power at 2 value instead of the full segments length
Srgment length = 2^ (6, 7, 8, .... 19)

Copy link

Copy link

Preview URL: https://5513d867.betaflight-blackbox.pages.dev

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/user_settings_dialog.js (1)

663-671: Consider adding input validation for percentage values.

While the settings loading logic is correct, consider adding validation to ensure the percentage values are within acceptable ranges (0-100).

+// Add validation helper function
+function validatePercentage(value, min = 0, max = 100) {
+  const num = parseInt(value);
+  return Math.max(min, Math.min(max, isNaN(num) ? 0 : num));
+}

 $('.analyser-settings input[name="analyser-legend-top"]').val(
-  parseInt(currentSettings.analyser_legend.top),
+  validatePercentage(currentSettings.analyser_legend.top),
 );
 $('.analyser-settings input[name="analyser-legend-left"]').val(
-  parseInt(currentSettings.analyser_legend.left),
+  validatePercentage(currentSettings.analyser_legend.left),
 );
 $('.analyser-settings input[name="analyser-legend-width"]').val(
-  parseInt(currentSettings.analyser_legend.width),
+  validatePercentage(currentSettings.analyser_legend.width),
 );
src/graph_imported_curves.js (1)

37-49: Consider performance optimization for large datasets.

The current implementation updates min/max values for every point, which could be inefficient for large datasets. Consider batch processing or using more efficient algorithms.

+// Process min/max in batches for better performance
+const xs = curvesData.map(point => point.x);
+const ys = curvesData.map(point => point.y);
+_that.minX = Math.min(_that.minX, Math.min(...xs));
+_that.maxX = Math.max(_that.maxX, Math.max(...xs));
+_that.minY = Math.min(_that.minY, Math.min(...ys));
+_that.maxY = Math.max(_that.maxY, Math.max(...ys));
src/graph_spectrum_plot.js (2)

60-68: Consider supporting more than 5 imported curves.

The curvesColors array only contains 5 colors, which limits the number of distinguishable imported curves. If users import more than 5 curves, the colors will be undefined.

Consider implementing a color generation function or expanding the color palette:

-  curvesColors : [
-    "Blue",
-    "Purple",
-    "DeepPink",
-    "DarkCyan",
-    "Chocolate",
-  ],
+  curvesColors : [
+    "Blue",
+    "Purple", 
+    "DeepPink",
+    "DarkCyan",
+    "Chocolate",
+    "Orange",
+    "Green",
+    "Red",
+    "Gold",
+    "Lime",
+  ],
+  getCurveColor: function(index) {
+    // Cycle through colors if more curves than colors
+    return this.curvesColors[index % this.curvesColors.length];
+  },

274-274: Consider making the filter window size configurable.

The filter window size has been increased from 50 to 200, which may impact performance when rendering multiple curves. Consider making this value configurable based on performance requirements.

-    const filterPointsCount = 200;
+    const filterPointsCount = this._importedSpectrums.getFilterWindowSize() || 200;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea0e023 and 5513d86.

📒 Files selected for processing (9)
  • index.html (3 hunks)
  • public/js/webworkers/spectrum-export-worker.js (1 hunks)
  • src/css/main.css (2 hunks)
  • src/graph_imported_curves.js (1 hunks)
  • src/graph_spectrum.js (9 hunks)
  • src/graph_spectrum_calc.js (2 hunks)
  • src/graph_spectrum_plot.js (38 hunks)
  • src/main.js (3 hunks)
  • src/user_settings_dialog.js (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • index.html
  • src/graph_spectrum_calc.js
  • src/css/main.css
  • src/graph_spectrum.js
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
public/js/webworkers/spectrum-export-worker.js (4)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-05-14T08:52:53.032Z
Learning: The FFT.complex library in Betaflight Blackbox Log Viewer provides two main methods: simple(output, input, type) and process(output, outputOffset, outputStride, input, inputOffset, inputStride, type). The 'simple' method is the one currently used in the codebase, while 'process' offers more granular control over memory layout with offsets and strides.
src/user_settings_dialog.js (1)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
src/graph_imported_curves.js (1)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
src/graph_spectrum_plot.js (4)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
src/main.js (3)
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.
Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#829
File: src/graph_spectrum_calc.js:332-335
Timestamp: 2025-05-12T19:49:35.667Z
Learning: In the Blackbox Log Viewer, the `_getFlightSamplesFreq()` function should return a sliced array `samples.slice(0, samplesCount)` rather than the full preallocated array, as code that consumes this function expects the array length to match the count of valid samples.
🔇 Additional comments (14)
public/js/webworkers/spectrum-export-worker.js (3)

4-4: LGTM: Spectrum data length calculation updated.

The change from half-length to full-length processing aligns with the broader spectrum data handling improvements in this PR.


7-7: LGTM: Generic CSV headers for broader compatibility.

The change from frequency-specific headers ("freq", "value") to generic headers ("x", "y") makes the export format more versatile for different spectrum types.


8-10: LGTM: Loop iteration updated for full data range.

The loop now processes all spectrum data points instead of half, which is consistent with the spectrumDataLength calculation change.

src/user_settings_dialog.js (2)

234-238: LGTM: New analyser legend settings structure.

The new analyser_legend settings group follows the established pattern with proper percentage-based positioning and sizing properties.


309-313: LGTM: UI-to-settings conversion properly implemented.

The conversion logic correctly reads the input values and formats them as percentage strings, consistent with other UI components.

src/main.js (3)

1152-1157: LGTM: Dynamic filename retrieval with proper error handling.

The change to dynamically obtain the export filename from the analyser and the null check with early return provides better error handling and flexibility.


1741-1741: LGTM: Function call updated for new signature.

The call to exportSpectrumToCsv() correctly removes the file parameter argument to match the updated function signature.


1752-1752: LGTM: Method name updated for consistency.

The method name change from clearImportedSpectrums() to removeImportedSpectrums() provides better semantic clarity.

src/graph_imported_curves.js (3)

1-12: LGTM: Well-structured module with clear initialization.

The module structure is clean with proper initialization of bounds and clear method definitions.


51-56: LGTM: Proper curve data structure and storage.

The curve data structure is well-defined with meaningful properties and proper storage in the internal array.


67-74: LGTM: Clean removal implementation.

The removeCurves method properly clears all data and resets bounds to initial values, ensuring consistent state management.

src/graph_spectrum_plot.js (3)

1604-1644: Good implementation of context-aware PSD value display.

The code correctly handles two different scenarios:

  1. For a single PSD spectrum - shows the PSD value at the mouse frequency
  2. For multiple imported PSD curves - shows the Y-axis value

This provides appropriate user feedback based on the viewing context.


1778-1790: Well-structured import method with appropriate error handling.

The method correctly delegates to the appropriate ImportedCurves instance based on spectrum type and provides helpful warnings for unsupported types.

Consider returning a boolean to indicate success/failure:

 GraphSpectrumPlot.importCurvesFromCSV = function(files) {
   switch (this._spectrumType) {
     case SPECTRUM_TYPE.FREQUENCY:
       this._importedSpectrums.importCurvesFromCSV(files);
+      return true;
       break;
     case SPECTRUM_TYPE.POWER_SPECTRAL_DENSITY:
       this._importedPSD.importCurvesFromCSV(files);
+      return true;
       break;
     default:
       console.warn(`Import not supported for spectrum type: ${this._spectrumType}`);
+      return false;
       break;
   }
 };

433-461: No action needed: ignore undefined userSettings and encapsulation flags.

The method’s use of userSettings is consistent with the rest of the codebase—globalThis.userSettings is initialized in src/main.js and treated as a global throughout all graph modules. Likewise, importedCurves[row].name accesses a public property; there’s no _curvesData or private‐field breach.

Likely an incorrect or invalid review comment.

Comment on lines +14 to +29
this.importCurvesFromCSV = function(files) {
let importsLeft = maxImportCount - this._curvesData.length;

for (const file of files) {
if (importsLeft-- == 0) {
break;
}
const reader = new FileReader();
reader.onload = function (e) {
try {
const stringRows = e.target.result.split("\n");

const header = stringRows[0].split(",");
if (header.length != 2 || header[0] != "x" || header[1] != "y") {
throw new SyntaxError("Wrong curves CSV data format");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance CSV validation and error handling.

The CSV parsing logic has several areas for improvement:

  1. The header validation could be more flexible
  2. Missing validation for numeric values
  3. Consider trimming whitespace from CSV values
 const header = stringRows[0].split(",");
-if (header.length != 2 || header[0] != "x" || header[1] != "y") {
+if (header.length != 2 || header[0].trim() != "x" || header[1].trim() != "y") {
   throw new SyntaxError("Wrong curves CSV data format");
 }

Additionally, consider adding validation for the parsed numeric values:

 const curvesData = stringRows.map( function(row) {
   const data = row.split(","),
-        x = parseFloat(data[0]),
-        y = parseFloat(data[1]);
+        x = parseFloat(data[0].trim()),
+        y = parseFloat(data[1].trim());
+  if (isNaN(x) || isNaN(y)) {
+    throw new SyntaxError(`Invalid numeric values in CSV: ${row}`);
+  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/graph_imported_curves.js around lines 14 to 29, improve the CSV
validation by making the header check more flexible to allow for whitespace and
case variations, trim whitespace from all CSV values before processing, and add
validation to ensure that the parsed x and y values are numeric. Update the code
to trim each header and data value, verify the header columns
case-insensitively, and check that each x and y value can be converted to a
valid number, throwing an error if not.


canvasCtx.beginPath();
canvasCtx.lineWidth = 1;
canvasCtx.strokeStyle = curvesColors[spectrumNum];
canvasCtx.strokeStyle = this.curvesColors[spectrumNum];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent undefined colors for curves beyond the color array length.

Direct array access will return undefined for indices >= 5, potentially causing rendering issues.

Use a modulo operation or the suggested getCurveColor method:

-    canvasCtx.strokeStyle = this.curvesColors[spectrumNum];
+    canvasCtx.strokeStyle = this.curvesColors[spectrumNum % this.curvesColors.length];

Also applies to: 375-375, 456-456

🤖 Prompt for AI Agents
In src/graph_spectrum_plot.js at line 272 (and similarly at lines 375 and 456),
the code directly accesses this.curvesColors with spectrumNum, which can be out
of bounds and return undefined. To fix this, replace direct array access with a
modulo operation on spectrumNum against the length of this.curvesColors or use
the existing getCurveColor method to safely retrieve a valid color, ensuring no
undefined colors are used for rendering.

Comment on lines +265 to +267
const spectrumCount = this._importedSpectrums.curvesCount();
for (let spectrumNum = 0; spectrumNum < spectrumCount; spectrumNum++) {
const curvesPonts = this._importedSpectrumsData[spectrumNum].points;
const curvesPonts = this._importedSpectrums._curvesData[spectrumNum].points;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use consistent API for accessing ImportedCurves data.

The code inconsistently uses curvesCount() method but directly accesses the private _curvesData property. This violates encapsulation principles.

The ImportedCurves class should provide public methods to access curve data:

-  const spectrumCount =  this._importedSpectrums.curvesCount();
-  for (let spectrumNum = 0;  spectrumNum < spectrumCount; spectrumNum++) {
-    const curvesPonts = this._importedSpectrums._curvesData[spectrumNum].points;
+  const spectrumCount =  this._importedSpectrums.curvesCount();
+  for (let spectrumNum = 0;  spectrumNum < spectrumCount; spectrumNum++) {
+    const curvesPonts = this._importedSpectrums.getCurvePoints(spectrumNum);

Also applies to: 369-371

🤖 Prompt for AI Agents
In src/graph_spectrum_plot.js around lines 265 to 267 and also lines 369 to 371,
the code uses the public method curvesCount() but directly accesses the private
property _curvesData, breaking encapsulation. To fix this, replace direct
accesses to _curvesData with appropriate public getter methods provided by the
ImportedCurves class to retrieve curve data, ensuring all interactions with
curve data go through the class's public API.

@demvlad demvlad changed the title Power spectral density curves settings impromement Power spectral density curves settings improvement Jul 16, 2025
@demvlad demvlad marked this pull request as draft July 16, 2025 16:43
@demvlad
Copy link
Contributor Author

demvlad commented Jul 16, 2025

@coderabbitai thank's for all notices.
This PR will like finally refactoring, i think

Copy link

coderabbitai bot commented Jul 16, 2025

Tip

For best results, initiate chat on the files or code changes.

@demvlad You're very welcome! It's great to see this PSD segment length improvement come together so well. The refactoring looks solid, and the new numeric input approach for controlling the Welch method parameters is much more intuitive than the previous slider. The modularization of the imported curves handling and the filter alignment fixes are excellent improvements too.

Best of luck with the final stages of this PR! 🐰

  (\   /)
 ( ^.^ )
o_(")(")

🧠 Learnings used
Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#0
File: :0-0
Timestamp: 2025-06-29T18:40:50.980Z
Learning: In betaflight/blackbox-log-viewer, when implementing PSD heatmap settings persistence in src/graph_spectrum.js, the initialization sequence is critical - user settings must be initialized and applied to GraphSpectrumPlot before attaching input event handlers to prevent spurious refresh() calls that can cause spectrum rendering errors when disabled.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#833
File: src/graph_spectrum.js:0-0
Timestamp: 2025-05-26T16:18:25.863Z
Learning: In src/graph_spectrum_calc.js, the user created dedicated PSD functions `dataLoadPowerSpectralDensityVsThrottle()` and `dataLoadPowerSpectralDensityVsRpm()` instead of using boolean parameters, following a consistent naming pattern for spectrum data loading methods.

Learnt from: nerdCopter
PR: betaflight/blackbox-log-viewer#822
File: .github/workflows/deploy-preview.yml:17-19
Timestamp: 2025-05-14T16:08:27.254Z
Learning: For betaflight/blackbox-log-viewer repository, the team is aware of the security implications of using `pull_request_target` without specifying `persist-credentials: false` in the checkout action, and has chosen to proceed with the current approach. This concern should not be flagged in future reviews.

Learnt from: demvlad
PR: betaflight/blackbox-log-viewer#827
File: src/graph_spectrum.js:200-207
Timestamp: 2025-05-10T19:47:41.430Z
Learning: The vertical zoom slider recalculation in the spectrum analyzer is designed to work only for POWER_SPECTRAL_DENSITY spectrum type, not for PSD_VS_THROTTLE or PSD_VS_RPM types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants